package com.szxx.mahjong.qianjiang.processor;


import com.szxx.base.server.GameSocketServer;
import com.szxx.config.SystemConfig;
import com.szxx.constant.ConstantCode;
import com.szxx.constant.GameConstant;
import com.szxx.domain.GameRoom;
import com.szxx.domain.GameTable;
import com.szxx.domain.MahjongCheckResult;
import com.szxx.domain.Player;
import com.szxx.mahjong.qianjiang.constans.GameRule;
import com.szxx.msg.*;
import com.szxx.processor.logic.GameLogicProcessor;
import com.szxx.processor.mahjong.MahjongProcessor;
import com.szxx.rule.DealRule;
import com.szxx.rule.WashCardRule;
import com.szxx.service.IMachineService;
import com.szxx.service.IPlayerService;
import com.szxx.service.ISystemConfigService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import java.util.ArrayList;
import java.util.List;


public class QianjiangGameLogicProcessor extends GameLogicProcessor {
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(QianjiangGameLogicProcessor.class);

    @Value("${zuoPaiFilePath:config/zuopai.txt}")
    private String zuoPaiFilePath;

    public QianjiangGameLogicProcessor(IPlayerService playerService, IMachineService machineService, ISystemConfigService systemConfigService, MahjongProcessor mahjongProcessor, DealRule dealRule, WashCardRule washCardRule) {
        super(playerService, machineService, systemConfigService, mahjongProcessor, dealRule, washCardRule);
    }


    @Override
    public void playerOperation(PlayerTableOperationMsg msg, Player player) {
        if (msg == null || player == null)
            return;
        int operation = msg.getOperation();
        // 查找vip房间
        if (operation == GameConstant.MAHJONG_OPERTAION_SEARCH_VIP_ROOM) {
            search_vip_room(msg, player);
            return;
        }
        GameRoom gameRoom = this.getRoom(player.getRoomID());
        if (gameRoom == null)
            return;
        if (operation == GameConstant.MAHJONG_OPERTAION_GAME_OVER_CHANGE_TABLE) {
            // 桌子可能已经撤掉了
            // 游戏结束，换桌
            // 记录roomid
            int roomID = player.getRoomID();
            // 先离开
            playerLeftTable(player);
            // 再加入
            tryEnterRoom(player, roomID);
            return;
        }
        // 游戏结束，继续，开始
        else if (operation == GameConstant.MAHJONG_OPERTAION_GAME_OVER_CONTINUE) {
            game_continue(player);
            return;
        }

        GameTable gameTable = gameRoom.getTable(player.getTableID());
        if (gameTable == null) {
            return;
        }

        if (msg.operation == GameConstant.MAHJONG_OPERTAION_SITDOWN) {
            readyForMahjongOpening(msg, player);
            return;
        }

        if (msg.operation == GameConstant.MAHJONG_OPERTAION_CANCEL_SITDOWN) {
            cancelReadyForMahjongOpening(msg, player);
            return;
        }

        // 有玩家同意关闭房间
        if (operation == GameConstant.MAHJONG_OPERTAION_WAITING_OR_CLOSE_VIP) {
            close_vip_table(msg, player);
            return;
        }

        // 序号检查
        if (gameTable.isVipTable() && !this.checkMsgSeq(msg, player, gameTable)) {
            return;
        }

        // 获取关闭房间全量
        if (operation == GameConstant.MAHJONG_OPERTAION_GET_CLOSE_VIP_ROOM_MSG) {
            this.sendCloseVipTableAck(gameTable, false, player);
            return;
        }

        // 剩余多少张牌
        msg.cardLeftNum = gameTable.getCardLeftNum();

        // 玩家出牌
        if ((operation & GameConstant.MAHJONG_OPERTAION_CHU) == GameConstant.MAHJONG_OPERTAION_CHU) {
            if (player.getOverTimeState() == GameConstant.PALYER_GAME_OVERTIME_STATE_IN_TABLE_WAITING_TO_OVERTIMECHU) {
                return;
            }
            this.playerChuOperation(gameRoom, gameTable, msg, player);
        } else if ((operation
                & GameConstant.MAHJONG_OPERTAION_OVERTIME_AUTO_CHU) == GameConstant.MAHJONG_OPERTAION_OVERTIME_AUTO_CHU) {
            if (player.getOverTimeState() == GameConstant.PALYER_GAME_OVERTIME_STATE_IN_TABLE_NOWAITING_TO_OVERTIMECHU)
                return;
            msg.operation = GameConstant.MAHJONG_OPERTAION_CHU;
            logger.info("当前玩家=" + player.getPlayerName() + " player_op_chu" + ",tableID=" + player.getTableID());
            playerChuOperation(gameRoom, gameTable, msg, player);

        }
        // 玩家吃牌
        else if ((operation & GameConstant.MAHJONG_OPERTAION_CHI) == GameConstant.MAHJONG_OPERTAION_CHI) {
            gameTable.setGangPlayer(null);
            player_op_chi(gameRoom, gameTable, msg, player);

        }
        // 玩家碰牌
        else if ((operation & GameConstant.MAHJONG_OPERTAION_PENG) == GameConstant.MAHJONG_OPERTAION_PENG) {
            player_op_peng(gameRoom, gameTable, msg, player);
        }

        //玩家杠牌，不管啥杠，客户端都发的这个明杠参数，服务器自己会判断是什么杠，客户端用这个MAHJONG_OPERTAION_MING_GANG
        else if ((operation & GameConstant.MAHJONG_OPERTAION_MING_GANG) == GameConstant.MAHJONG_OPERTAION_MING_GANG) {
            player_op_gang(gameRoom, gameTable, msg, player);

        }
        // 玩家去消吃碰牌
        else if ((operation & GameConstant.MAHJONG_OPERTAION_CANCEL) == GameConstant.MAHJONG_OPERTAION_CANCEL) {
            player_cancel_chi_peng_gang_hu(gameRoom, gameTable, msg, player);
        } else if ((operation & GameConstant.MAHJONG_OPERTAION_HU) == GameConstant.MAHJONG_OPERTAION_HU) {
            player_op_hu(gameTable, msg, player);
        } else if ((operation & GameConstant.MAHJONG_OPERTAION_POP_LAST) == GameConstant.MAHJONG_OPERTAION_POP_LAST) {
            // 取得杠牌后抓的尾牌
            player_op_get_gang_card(gameRoom, gameTable, msg, player);
        }
    }

    @Override
    public void enterVipRoom(EnterVipRoomMsg msg, Player player) {
        GameRoom rm = null;
        GameTable gt = null;
        //
        if (msg.getTableID().equals("enter_room")) {
            int vip_table_id = msg.getRoomID();
            msg.setRoomID(2002);//中级场
            //
            rm = gameRoomMap.get(2002);
            if (rm != null)
                gt = rm.getVipTableByVipTableID(vip_table_id);
        } else if (msg.getTableID().equals("ask_enter_room")) {//进入房间前先拉去房间信息，弹提示
            int vip_table_id = msg.getRoomID();
            msg.setRoomID(2002);
            rm = gameRoomMap.get(2002);
            gt = rm.getVipTableByVipTableID(vip_table_id);
            if (gt != null && !gt.isFull()) {
                RequestStartGameMsgAck info = new RequestStartGameMsgAck();
                info.setNewPlayWay(gt.getVipRule());
                info.setDiZhu(gt.getBaseGold());
                info.setPayType(gt.isDiamondAA() ? 1 : 0);
                info.setResult(ConstantCode.VIP_ROOM_EXIT);
                /*
                RequestTableInfoAckMsg info = new RequestTableInfoAckMsg();
                info.is_share_fangka = gt.isDiamondAA()?1:0;
                SystemConfigPara config = cfgService.getPara(GameConfigConstant.CONF_IS_VIP_FREE);
                //免费房卡
                if(config.getValueInt() == 1){
                    info.is_free=1;
                }
                info.play_type=gt.getVip_rule();
                info.use_fangka = playerService.getTableDiamondCost(gt.getBaseHandsTotal());
                info.hand_num=gt.getBaseHandsTotal();
                info.vip_table_id = gt.getVipTableID();
                */
                info.setVipTableID(gt.getVipTableID());
                info.setTotalHand(gt.getBaseHandsTotal());
                info.sessionID = player.getPlayerLobbySessionID();
                playerService.addThreadPlayer(player, logicThreadId);
                SystemConfig.gameSocketServer.sendMsg(player.getSession(), info);
                return;
            } else {
                RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
                ack.setGold(player.getGold());
                ack.setResult(ConstantCode.VIP_TABLE_NOT_FOUND);
                //进入桌子，返回消息给玩家
                ack.sessionID = player.getPlayerLobbySessionID();
                SystemConfig.gameSocketServer.sendMsg(player.getSession(), ack);
                return;
            }
        } else {
            rm = gameRoomMap.get(msg.getRoomID());
            if (rm == null) {
                logger.error("enterVipRoom,rm==null, playerIndex={}", player.getPlayerIndex());
                return;
            }
            playerService.addThreadPlayer(player, logicThreadId);
            gt = rm.getTable(msg.getTableID());
        }
        if (gt == null) {
            RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
            ack.setGold(player.getGold());
            //
            ack.setResult(ConstantCode.VIP_TABLE_NOT_FOUND);
            playerService.delThreadPlayer(player);
            //进入桌子，返回消息给玩家
            ack.sessionID = player.getPlayerLobbySessionID();
            SystemConfig.gameSocketServer.sendMsg(player.getSession(), ack);
            logger.error("enterVipRoom,rm==null, playerIndex={}", player.getPlayerIndex());
            return;
        }
        //现在不校验密码
        //密码错误
//		if(gt.getVipPswMd5().equals(msg.psw)==false)
//		{
//			RequestStartGameMsgAck ack=new RequestStartGameMsgAck();
//			ack.gold=pl.getGold();
//			//
//			ack.result=ErrorCodeConstant.WRONG_PASSWORD;
//			//进入桌子，返回消息给玩家
//			ack.sessionID=pl.getPlayerLobbySessionID();
//			SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
//			return;
//		}
        //如果创建房间没有设置底注，则取数据库配置
        if (gt.getBaseGold() == 0) {
            gt.setBaseGold(rm.getPrice());
        }

        //
        int old_tablePos = findPlayerIndex(player, gt);
        boolean old_table = false;
        if (old_tablePos >= 0) {//已经存在，离开又进来
            old_table = true;
            player.setTableID(gt.getTableID());
            player.setVipTableID(gt.getTableID());

        } else {
            if (gt.isFull()) {
                RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
                ack.setGold(player.getGold());
                //
                ack.setResult(ConstantCode.VIP_TABLE_IS_FULL);
                playerService.delThreadPlayer(player);
                //进入桌子，返回消息给玩家
                ack.sessionID = player.getPlayerLobbySessionID();
                SystemConfig.gameSocketServer.sendMsg(player.getSession(), ack);

                return;
            }
            if (gt.isDiamondAA() && gt.getHandNum() == 0) {
                int diamond_need = playerService.getTableDiamondCost(gt.getBaseHandsTotal());
                if (player.getDiamond() < diamond_need / 4) {
                    logger.info("check share diamond not enough:" + player.getPlayerIndex());
                    RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
                    ack.setGold(player.getDiamond());
                    ack.setResult(ConstantCode.FANGKIA_NOT_FOUND);
                    playerService.delThreadPlayer(player);
                    ack.sessionID = player.getPlayerLobbySessionID();
                    SystemConfig.gameSocketServer.sendMsg(player.getSession(), ack);
                    return;
                }
            }
            gt.enterPlayer(player);
        }
        //如等待玩家中，满了就开始，如果中间断线再进入，就不要这个状态切换
        // 如等待玩家中，满了就开始，如果中间断线再进入，就不要这个状态切换
        if (!gt.isNeedReadyBeforePlaying() && gt.isFull() && gt.getState() == GameConstant.GAME_TABLE_STATE_WAITING_PLAYER) {
            gt.setState(GameConstant.GAME_TABLE_STATE_READY_GO);
        }

        player.setRoomID(msg.getRoomID());
        player.setTableID(gt.getTableID());
        player.setVipTableID(String.valueOf(gt.getVipTableID()));

        boolean re_enter = false;
        if (old_table && gt.isFull())
            re_enter = true;

        enterTableDone(player, gt, re_enter, false);
    }

    public int findPlayerIndex(Player ply, GameTable gameTable) {
        int idx = -1;
        for (int i = 0; i < gameTable.getPlayers().size(); i++) {
            Player pl = gameTable.getPlayers().get(i);
            if (pl.getPlayerID().equals(ply.getPlayerID())) {
                idx = pl.getTablePos();

                if (idx >= 0 && (ply.getTablePos() != idx || ply.isNeedCopyGameState())) {
                    logger.error("玩家:" + ply.getPlayerIndex() + "断线重连，游戏数据异常，old_tablePos=" + idx + ",tablePos=" + ply.getTablePos()
                            + ",old_vipTableGold=" + pl.getVipTableGold() + ", vipTableGold=" + ply.getVipTableGold());

                    //复制玩家的游戏数据
                    ply.copy_game_state(pl);
                    ply.setOnTable(true);
                    ply.setOnline(true);
                    ply.setNeedCopyGameState(false);

                    //替换桌子保存的玩家数据
                    gameTable.getPlayers().set(i, ply);
                }

                break;
            }
        }
        return idx;
    }

    public void playerChuNotify(GameTable gt, boolean couldHu, boolean couldGang) {
        Player plx = gt.getCurrentOperationPlayer();
        if (plx == null)
            return;

        logger.info("player_chu_notify, playerIndex=" + plx.getPlayerIndex() + " tableID=" + plx.getTableID());
        //
        byte newCard = plx.getCardGrab();

        PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();

        MahjongCheckResult wait = new MahjongCheckResult();
        wait.playerTableIndex = plx.getTablePos();
        wait.opertaion = 0;
        wait.targetCard = newCard;

        //
        MahjongCheckResult hu_xx = null;
        //
        boolean player_could_hu = false;

        if (couldHu && hu_xx == null) {//例如玩家碰完不能直接胡，必须出一张；例如玩家手里剩4张2对，别人出牌他不胡，碰，碰完也不能胡，必须打出一张
            hu_xx = mahjongProcessor.checkWin(newCard, plx, gt);

            if (hu_xx != null)//胡了
            {
                logger.info(plx.getPlayerIndex() + ":可以胡牌了!");
                player_could_hu = true;
            }
        }

        //提示玩家出牌
        msg.operation |= GameConstant.MAHJONG_OPERTAION_CHU;
        msg.playerTablePos = plx.getTablePos();
        msg.chiCardValue = newCard;
        msg.cardLeftNum = gt.getCardLeftNum();
        msg.chiFlag = 0;//plx.getCouldNotChuCards();

        //自己摸，看看各种杠
        MahjongCheckResult gang_result = null;
        if (couldGang) {
            gang_result = mahjongProcessor.checkGang(gt, newCard, plx, true);
        }

        if (gang_result != null) {
            byte hu_card = 0x0;

            //提示玩家听牌，也可以出牌
            msg.gangList = gang_result.gangList;
            msg.pengCardValue = gang_result.pengCardValue;
            msg.operation |= gang_result.opertaion;
            //
            wait.pengCardValue = gang_result.pengCardValue;
            wait.chiCardValue = hu_card;
            wait.gangList = gang_result.gangList;
            logger.info("waitting gang size:" + wait.gangList.size());
        }

        if (player_could_hu) {
            msg.operation |= GameConstant.MAHJONG_OPERTAION_HU;
            if ((hu_xx.fanResult & GameRule.MAHJONG_HU_CODE_HEIMO) != 0) {
                msg.huStyle = GameRule.MAHJONG_HU_CODE_HEIMO;
                wait.fanResult |= GameRule.MAHJONG_HU_CODE_HEIMO;
            }
        }
        //
        wait.opertaion = msg.operation;

        int waitFan = getWaitFan(gt);
        wait.addFanResult(waitFan);
        if ((wait.fanResult & GameConstant.MAHJONG_HU_CODE_FANG_GANG_HU) != 0) {
            wait.chuPlayer = gt.getWaitingPlayerOperate().chuPlayer;
        }

        gt.setWaitingPlayerOperate(wait);
        plx.setOpStartTime(System.currentTimeMillis());

        //
        //发给其他玩家，让他们知道当前轮到谁操作
        PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
        msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
        msg2.cardLeftNum = gt.getCardLeftNum();
        msg2.playerTablePos = plx.getTablePos();
        this.sendMsgToTable(gt, msg2, 1);

        //
        if (plx.isRobot()) {
            machineService.postMsg(gt, plx, msg);
        }

        //发消息给玩家，提示他出牌
        msg.sessionID = plx.getPlayerLobbySessionID();
        SystemConfig.gameSocketServer.sendMsgWithSeq(plx.getSession(), msg, plx.getPlayerID(), gt);
    }

    @Override
    protected void notifyNextPlayerOperation(GameTable gt) {
        byte card = gt.getCurrentCard();
        Player chuPlayer = gt.getPlayerAtIndex(gt.getCardOpPlayerIndex());
        byte laizi = gt.getLazarailloCard();
        Player pl = gt.getCurrentOperationPlayer();
        if (laizi == card) {
            byte tailCd = gt.popLastCard(1);
            pl.setCardGrab(tailCd);
            //如果桌上没牌了，出癞子流局
            if (gt.isEnd()) {//流局了
                gameOverLiuju(gt);
                return;
            }
            pl.addCardDown(laizi, laizi, laizi, GameRule.MAHJONG_OPERTAION_LAIZI_GANG);
            MahjongCheckResult waiting = new MahjongCheckResult();
            waiting.playerTableIndex = chuPlayer.getTablePos();
            waiting.targetCard = chuPlayer.getCardGrab();
            waiting.fanResult |= GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
            gt.setWaitingPlayerOperate(waiting);
            chu_end(gt);
            playerChuNotify(gt, true, true);//杠完能胡
            return;
        }
        //顺序，轮到下一个玩家行动
        gt.moveToNextPlayer();
        Player plx = gt.getCurrentOperationPlayer();
        if (plx == null) {
            return;
        }

        if (gt.isEnd()) {//流局了
            //最后一张打出的不能胡
            checkNextPlayerOperation(gt, card, chuPlayer, GameConstant.MAHJONG_OPERTAION_HU);
            //game_over_liuju(gt);
            return;
        } else {
            //可以吃，碰，杠， 点炮
            //潜江麻将不能吃
            checkNextPlayerOperation(gt, card, chuPlayer,
                    GameConstant.MAHJONG_OPERTAION_PENG
                            | GameConstant.MAHJONG_OPERTAION_MING_GANG
                            | GameConstant.MAHJONG_OPERTAION_HU);
        }
    }

    private void gameOverLiuju(GameTable gt) {
        //流局不流局，杠必须算分
        mahjongProcessor.goldCalculateLiuju(gt);
        gt.setLiuJuNoPlayerHu(true);

        //合并计算提交数据库
        win_lose_money_submit(gt);
        //
        gt.setState(GameConstant.GAME_TABLE_STATE_SHOW_GAME_OVER_SCREEN);

        //
        long ctt = System.currentTimeMillis();
        gt.setHandEndTime(ctt);
    }

    /**
     * 杠牌动画播完
     *
     * @param gt
     * @param waitTime
     */
    @Override
    protected void watingGangAnimation(GameTable gt, int waitTime) {
        long currentTime = System.currentTimeMillis();
        // 动画播完
        boolean isOver = currentTime - gt.getWaitingStartTime() > 1000 + waitTime;
        if (isOver) {
            gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_IDLE);
            //吃完，碰完不能立刻胡
            boolean could_hu = true;

            Player pl = gt.getCurrentOperationPlayer();

            //如果是痞子笑不摸牌
            if (gt.getCurrentCard().byteValue() != gt.getRiffraffCard()) {
                //判断2个底牌是否杠开，如果可以刚开，上花
                byte cd = gt.popLastCard(1);
                pl.setCardGrab(cd);
            } else {
                //痞子笑之后不能胡
                could_hu = false;
            }

            gt.setCurrentCard((byte) 0);
//            waiting = new MahjongCheckResult();
//            waiting.playerTableIndex = pl.getTablePos();
//            waiting.targetCard = pl.getCardGrab();
//            waiting.fanResult |= GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
//            gt.setWaitingPlayerOperate(waiting);

            //通知玩家出牌
            playerChuNotify(gt, could_hu, true);
        }
    }

    @Override
    public void createVIPTable(Player pl, CreateVipRoomMsg msg) {
        GameRoom rm = gameRoomMap.get(msg.getRoomID());
        if (rm == null) {
            return;
        }

        String vip_tb_id = pl.getVipTableID();
        if (vip_tb_id != null && vip_tb_id.length() > 1 && rm.getPlayingTablesMap().containsKey(vip_tb_id)) {
            logger.error("player index:" + pl.getPlayerIndex() + ",md5:" + msg.getPsw() + ",ordin vip_rule:" + msg.getSelectWayNum() + ",vip tableid:" + pl.getVipTableID());
            return;
        }
        GameTable gt = rm.createVipTable(msg, pl);
        if (gt == null) {
            return;
        }
        gt.setBaseHandsTotal(msg.getQuanNum());
        logger.info("tableid=" + gt.getVipTableID() + ",hands=" + msg.getQuanNum() + ",vip_rule=" + msg.getSelectWayNum());

        //vip默认具有的打法，毋须客户端配置
        //int default_rule=rm.get_default_vip_table_rule(SystemConfig.mjType);
        //vip_rule |= default_rule;
        //设置规则方法
        gt.setNeedReadyBeforePlaying(msg.isNeedReadyBeforePlaying());
        gt.setBaseGold(msg.getDizhu());
        gt.setVipRule(msg.getSelectWayNum());
        // 设置剩余码数
        gt.setMaiMaNum(0);//具体看潜江玩法的码数
        if (msg.getPayType() != 0) {
            gt.setDiamondAA(true);
        }

        long ct = System.currentTimeMillis();
        gt.setVipCreateTime(ct);
        //总圈数
        gt.setHandsTotal(msg.getQuanNum());

        int diamond_need = playerService.getTableDiamondCost(msg.getQuanNum());
        if (msg.getPayType() != 0) {
            diamond_need = diamond_need / 4;
        }
        if (pl.getDiamond() < diamond_need) {
            RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
            ack.setGold(pl.getDiamond());
            //
            ack.setResult(ConstantCode.FANGKIA_NOT_FOUND);
            //
            ack.sessionID = pl.getPlayerLobbySessionID();
            SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
            return;
        }
        playerService.addThreadVipTable(pl, gt.getVipTableID(), gt.getTableID(), this.logicThreadId);
        //设置为未支付房卡
        gt.setPayVipKa(false);

        //设置VIP房间带入金额
        pl.setVipTableGold(0);

        pl.setOnTable(true);
        gt.setGameLogic(this);

        //返回给玩家，
        RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
        ack.setGold(pl.getGold());
        ack.setTotalHand(gt.getHandsTotal());
        ack.setCurrentHand(gt.getHandNum());
        ack.setDiZhu(msg.getDizhu());
        ack.setNewPlayWay(gt.getVipRule() & 0xffff);
        ack.setResult(ConstantCode.CMD_EXE_OK);
        ack.initPlayers(gt.getPlayers(), gt.isVipTable());
        ack.setRoomID(msg.getRoomID());
        ack.setTablePos(pl.getTablePos());
        ack.setVipTableID(gt.getVipTableID());
        ack.setCreatorName(gt.getCreatorPlayerName());
        ack.setCreatePlayerID(gt.getCreatorPlayerID());
        ack.setPayType(gt.isDiamondAA() ? 1 : 0);
        //进入桌子,发消息给玩家
        ack.sessionID = pl.getPlayerLobbySessionID();
        SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
        this.refreshClientSeq(gt, pl, 0);
    }

    @Override
    protected void deal(GameTable gameTable, int operationTime, int isDealerAgain) {
        if (logger.isDebugEnabled()) {
            logger.debug("开始发牌,桌子ID:{}", gameTable.getTableID());
        }
        //设置痞子癞子
        byte pizi = gameTable.getLast1Card();
        gameTable.popLastCard(1);    //去掉最后一张痞子
        byte laizi = 0;
        //if (testPizi > 0) pizi = (byte)testPizi;
        int color = pizi & 0xf0;
        int value = pizi & 0x0f;
        value = (value + 1) % 10;
        if (value == 0) {
            value = 0x01;
        }
        laizi = (byte) (color | value);
        gameTable.setRiffraffCard(pizi);
        gameTable.setLazarailloCard(laizi);
        // 使用发牌规则将牌发给玩家
        dealRule.dealCard(gameTable);
        // 将玩家的牌发给客户端
        for (Player player : gameTable.getPlayers()) {
            GameStartMsg msg = new GameStartMsg();
            msg.setNewPlayWay(gameTable.getVipRule());
            msg.setMyCards(player.getCardsInHand());
            msg.setMyTablePos(player.getTablePos());
            msg.setQuanNum(gameTable.getHandNum());
            msg.setDealerPos(gameTable.getDealerPos());
            msg.setBaoCard(pizi | laizi << 8);
            msg.setup_gold(gameTable.getPlayers(), gameTable.isVipTable());
            msg.setServiceGold(gameTable.getHandsTotal());
            msg.setPlayerOperationTime(operationTime);
            msg.setIsDealerAgain(isDealerAgain);
            msg.setSessionID(player.getPlayerLobbySessionID());
            GameSocketServer.sendMsgWithSeq(player.getSession(), msg, player.getPlayerID(), gameTable);
        }
    }

    @Override
    protected void player_op_hu(GameTable gt, PlayerTableOperationMsg msg, Player pl) {
        MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
        if (waiting == null) {
            logger.error("no such operation, PlayerIndex=" + pl.getPlayerIndex() + ",tableID=" + gt.getVipTableID() + ",handNum=" + gt.getHandNum());
            return;//当前没有在等待某个玩家操作；
        }

        if (waiting.playerTableIndex != pl.getTablePos()) {

            logger.error("player_op_hu,table position invalid,player_index=" + pl.getPlayerIndex() + ",tableID=" + gt.getVipTableID() + ",handNum=" + gt.getHandNum());
            return;//当前不是在等这个玩家操作
        }

        //
        if (((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_HU) != GameConstant.MAHJONG_OPERTAION_HU)) {
            logger.error("hu operation invalid" + ",tableID=" + gt.getVipTableID() + ",handNum=" + gt.getHandNum());
            return;//当前不能吃；
        }

        MahjongCheckResult hu_xx = mahjongProcessor.checkWin(waiting.targetCard, pl, gt);
        if (hu_xx == null) {
            logger.error("playerName=" + pl.getPlayerName() + " hu operation failed,card=" + waiting.targetCard + ",tableID=" + gt.getVipTableID() + ",handNum=" + gt.getHandNum());
            return;
        }

        if ((waiting.opertaion & GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) == GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) {
            hu_xx.fanResult |= GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
        }
        // 杠上炮、抢杠胡
        hu_xx.addFanResult(waiting.fanResult);

        //轮流胡牌逻辑start
        /*
        //玩家胡了
        this.player_hu(gt, pl, waiting.chuPlayer, hu_xx.fanResult, hu_xx.targetCard, hu_xx.keZiNum, hu_xx.same2Shunzi, hu_xx);
        if(pl.getHuPaoPL() == null){
            List<Player> huPlayers = new ArrayList<Player>();
            huPlayers.add(pl);
            //胡牌算分
            mjProc.win_lose_gold_calculate_hu(gt,huPlayers,waiting.chuPlayer);
            game_over_hu(gt, false);
            return;
        }

        //点炮胡走下面逻辑,判断一炮多响并让玩家点胡牌
        gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_HU_ANIMATION);
        */
        //轮流胡牌逻辑end

        //自动胡牌逻辑start
        //记录胡的玩家
        List<Player> huPlayers = new ArrayList<Player>();
        //玩家胡了
        this.player_hu(gt, pl, waiting.chuPlayer, hu_xx.fanResult, hu_xx.targetCard, hu_xx.keZiNum, hu_xx.same2Shunzi, hu_xx);

        //剩下几家就自动胡了
        if (waiting.chuPlayer != null){//看看是否有一炮多响
            auto_hu_other_player(gt, hu_xx.targetCard, pl, waiting.chuPlayer.getTablePos());
        }
        //记录胡的玩家
        List<Player> players = gt.getPlayers();
        for (Player player : players) {
            if (player.isWin()) {
                huPlayers.add(player);
            }
        }
        //如果一炮多响，庄家就是放炮的人
        if (huPlayers.size() > 1 && pl.getHuPaoPL() != null) {
            logger.info("一炮多响," + pl.getHuPaoPL().getPlayerIndex() + "玩家放炮" + ",tableID=" + gt.getVipTableID() + ",handNum=" + gt.getHandNum());
            gt.setCurrentHuPlayerIndex(pl.getHuPaoPL().getTablePos());
        }
        //胡牌算分
        mahjongProcessor.goldCalculateHu(gt, huPlayers, waiting.chuPlayer);

        game_over_hu(gt, false);
        //自动胡牌逻辑end
    }

    public void auto_hu_other_player(GameTable gt,byte card,Player opPlayer,int chuCardPlayerTableIndex) {

        List<Player> plist=gt.getPlayers();
        int pl_index=opPlayer.getTablePos()+1;
        if(pl_index>=plist.size())
            pl_index=0;
        //
        Player chuPl=gt.getPlayerAtIndex(chuCardPlayerTableIndex) ;
        //

        for(int i=0;i<plist.size()-1;i++)
        {
            Player pl=plist.get(pl_index);

            if(pl.getTablePos()==chuCardPlayerTableIndex)
                break;

            if(pl.isWin()==false)
            {
                //先检测卡胡
                MahjongCheckResult hu=mahjongProcessor.checkWin(card, pl,gt);

                if (hu != null) {
                    int waitFan = getWaitFan(gt);
                    hu.addFanResult(waitFan);
                }
                //
                if(hu!=null)
                {
                    this.player_hu(gt, pl,chuPl,hu.fanResult,hu.targetCard,hu.keZiNum,hu.same2Shunzi,hu);
                }
            }
            pl_index++;
            if(pl_index>=plist.size())
                pl_index=0;
        }
    }
}

